package com.eric.media.camera;


import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
import android.view.WindowManager;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 *
 * 照相机工具类 （已经过时了）
 * <h3>Description</h3>
 * TODO
 * <h3>Author</h3> Eric
 * <h3>Date</h3> 2017/9/26 16:58
 * <h3>Copyright</h3> Copyright (c)2017 Shenzhen TLKY  Co., Ltd. Inc. All rights reserved.
 */
public class CameraUtil {

    /**系统所用的照相机*/
    private  Camera camera;
    /**是否在预览中*/
    private  boolean isPreView;
    /**相机参数*/
    private Camera.Parameters parameters;
    /**照片高度和宽度*/
    private  int imgWidth = 0;
    private  int imgHeight = 0;
    /**用来展示预览画面*/
//    private SurfaceView surfaceView;
    private SurfaceHolder surfaceHolder;
    /** 照片的保存路径 */
    private String path ;
    /** 照片前缀*/
    public static final String IMG =   "IMG_";
    /** 照片的保存目录 */
    public static final String CAMERA =   "Camera";
    /**图片后缀*/
    public static final String JPEG =   ".jpg";
    /** true 表示正在拍照 在拍照的过程中不允许重新拍照 、重新对焦*/
    private boolean isTokingPicture = false;
    /** 高宽比*/
    private float ratio;
    private Context mContext;
    /** 线程池*/
    private ExecutorService executorService = Executors.newFixedThreadPool(10);

    private CameraUtil() {
    }

    private static class  CameraFactory {
        private static  CameraUtil cameraUtil = new CameraUtil();
    }

    public static CameraUtil getInstance() {
        return CameraFactory.cameraUtil;
    }

    /**
     * 初始化相机
     * 在这里做了如下业务：
     * 1  打开摄像头
     * 2  设置相机参数
     * 3  设置surfaceView 用于显示预览图片
     * 4  获取图片保存路径
     * @param  isFullScreen true全屏显示 否则不是最佳屏幕显示
     */
    public void initCamera(Context context,SurfaceView surfaceView , boolean isFullScreen) {
        this.mContext = context;
        WindowManager windowManager = null;
        if (context instanceof Activity){
            windowManager = ((Activity)context).getWindowManager();
        }
//        if (context instanceof AppCompatActivity){
//            windowManager = ((AppCompatActivity)context).getWindowManager();
//        }
        if (windowManager == null){
          throw  new RuntimeException("context need belong to Activity or AppCompatActivity !") ;
        }
        Display display = windowManager.getDefaultDisplay();
        DisplayMetrics metrics = new DisplayMetrics();
        display.getMetrics(metrics);
        imgWidth = metrics.heightPixels;
        imgHeight = metrics.widthPixels;

        ratio = (float) surfaceView.getWidth() / surfaceView.getHeight();

        getLocalSavePath(context);
        //此处默认打开后置摄像头
        //通过传入参数可以打开前置摄像头
        camera = Camera.open();
        if (camera != null){
            parameters = camera.getParameters();
            //设置照片格式。
            parameters.setPictureFormat(ImageFormat.JPEG);
            //设置摄像头自行对焦
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
//                parameters.setSceneMode(Camera.Parameters.SCENE_MODE_BARCODE);
//                List<String> focusModes = parameters.getSupportedFocusModes();
//                if(focusModes.contains("continuous-video")){
//                    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
//                }
            //闪光灯配置参数 自动模式
            parameters.setFlashMode(Camera.Parameters.FOCUS_MODE_AUTO);
            //场景模式配置参数
            parameters.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
            //设置照片的质量
            parameters.set("jpeg-quality",85);
            if (isFullScreen){
                //设置照片的大小
                parameters.setPictureSize(imgWidth, imgHeight);
                parameters.setPreviewSize(imgWidth,imgHeight);
                setSurfaceView(surfaceView,null);
            }else {
                // 设置pictureSize
                List<Camera.Size> pictureSizes = parameters.getSupportedPictureSizes();
                Camera.Size  picSize = findBestPictureSize(pictureSizes,parameters.getPictureSize(),ratio);
                //设置照片的大小
                parameters.setPictureSize(picSize.width, picSize.height);

                //设置预览照片的大小
                List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
                Camera.Size  preSize = findBestPreviewSize(previewSizes,parameters.getPreviewSize(),picSize,ratio);
                parameters.setPreviewSize(preSize.width, preSize.height);
                //设置预览照片时，每秒展示多少帧的最小值和最大值
//                parameters.setPreviewFpsRange(4,10);
                setSurfaceView(surfaceView,preSize);
            }


            /** java.lang.RuntimeException: setParameters failed */
            camera.setParameters(parameters);
            startPreview();
        }

    }

    /**
     * 请求对焦
     */
    public void requestFocus(){
        if (camera != null && !isTokingPicture){
            //在拍照的过程中不允许重新拍照 、重新对焦
            camera.autoFocus(autoFocusCallback);
        }
    }

    /**
     * 开始预览取景
     */
    public void startPreview() {
        if (null == camera ||  null == surfaceHolder ){
            return;
        }
        if (isPreView){
            camera.stopPreview();
            isPreView = false;
        }
        //设置surfaceView显示取景画面
        try {
            camera.setPreviewDisplay(surfaceHolder);
            //竖屏拍照，所以还需要对Camera旋转90
//            camera.setDisplayOrientation(90);
            followScreenOrientation(mContext,camera);
            camera.startPreview();
            isPreView = true;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 停止取景
     */
    public void stopPreview() {
        if (null != camera){
            if (isPreView){
                camera.stopPreview();
                isPreView = false;
            }
            camera.cancelAutoFocus();
            camera.release();
            camera = null;
        }
    }

    /**
     * 开始拍照
     */
    public void takePicture() {
        isTokingPicture = true;
        /**
         * takePicture 方法需要传入三个监听器参数
         * 1 用户按下快门时激发监听器
         * 2 相机获取原始照片时激发该监听器
         * 3 相机获取JPG照片时激发监听器
         */
        camera.takePicture(new Camera.ShutterCallback() {
            @Override
            public void onShutter() {

            }
        }, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {

            }
        }, new MyGetPictureCallback());
    }

    /**
     *  Camera.Parameters.FOCUS_MODE_AUTO 自动对焦模式，摄影小白专用模式；
        Camera.Parameters.FOCUS_MODE_FIXED 固定焦距模式，拍摄老司机模式；
        Camera.Parameters.FOCUS_MODE_EDOF 景深模式，文艺女青年最喜欢的模式；
        Camera.Parameters.FOCUS_MODE_INFINITY 远景模式，拍风景大场面的模式；
        Camera.Parameters.FOCUS_MODE_MACRO 微焦模式，拍摄小花小草小蚂蚁专用模式；
     * @return 场景模式
     */
    public String getSceneMode(){
        return parameters.getSceneMode();
    }

    /**
     * Camera.Parameters.FOCUS_MODE_AUTO 自动对焦模式，摄影小白专用模式；
     * Camera.Parameters.FOCUS_MODE_FIXED 固定焦距模式，拍摄老司机模式
     * Camera.Parameters.FOCUS_MODE_EDOF 景深模式，文艺女青年最喜欢的模式；
     * Camera.Parameters.FOCUS_MODE_INFINITY 远景模式，拍风景大场面的模式；
     * Camera.Parameters.FOCUS_MODE_MACRO 微焦模式，拍摄小花小草小蚂蚁专用模式；
     * @return 对焦模式
     */
    public String getFocusMode(){
        return parameters.getFocusMode();
    }

    /**
     *
     * Camera.Parameters.FLASH_MODE_AUTO 自动模式，当光线较暗时自动打开闪光灯；
     * Camera.Parameters.FLASH_MODE_OFF 关闭闪光灯；
     * Camera.Parameters.FLASH_MODE_ON 拍照时闪光灯；
     * Camera.Parameters.FLASH_MODE_RED_EYE 闪光灯参数，防红眼模式，科普一下：防红眼；
     * @return 闪光灯配置
     */
    public String getFlashMode(){
        return parameters.getFlashMode();
    }

    /**
     * 判断手机设备是否有相机设备
     * @param ctx
     * @return
     */
    public static boolean hasCameraDevice(Context ctx) {
        return ctx.getPackageManager()
                .hasSystemFeature(PackageManager.FEATURE_CAMERA);
    }

    /**
     * 判断是否支持自动对焦
     * @param params
     * @return
     */
    public static boolean isAutoFocusSupported(Camera.Parameters params) {
        List<String> modes = params.getSupportedFocusModes();
        return modes.contains(Camera.Parameters.FOCUS_MODE_AUTO);
    }

    /**
     * 对焦回调接口
     */
    Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {
        //当自动对焦激发该方法
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
            if (success){//对焦成功后开始拍照
                takePicture();
            }
        }
    };

    /**
     * 设置屏幕方向
     * @param context
     * @param camera
     */
    public  void followScreenOrientation(Context context, Camera camera){
        final int orientation = context.getResources().getConfiguration().orientation;
        if(orientation == Configuration.ORIENTATION_LANDSCAPE) {
            camera.setDisplayOrientation(180);
        }else if(orientation == Configuration.ORIENTATION_PORTRAIT) {
            camera.setDisplayOrientation(90);
        }
    }


    /**
     * 找到短边比长边大于于所接受的最小比例的最大尺寸
     *
     * @param sizes       支持的尺寸列表
     * @param defaultSize 默认大小
     * @param minRatio    相机图片短边比长边所接受的最小比例
     * @return 返回计算之后的尺寸
     */
    private Camera.Size findBestPictureSize(List<Camera.Size> sizes, Camera.Size defaultSize, float minRatio) {
        final int MIN_PIXELS = 320 * 480;

        sortSizes(sizes);

        Iterator<Camera.Size> it = sizes.iterator();
        while (it.hasNext()) {
            Camera.Size size = it.next();
            //移除不满足比例的尺寸
            if ((float) size.height / size.width <= minRatio) {
                it.remove();
                continue;
            }
            //移除太小的尺寸
            if (size.width * size.height < MIN_PIXELS) {
                it.remove();
            }
        }

        // 返回符合条件中最大尺寸的一个
        if (!sizes.isEmpty()) {
            return sizes.get(0);
        }
        // 没得选，默认吧
        return defaultSize;
    }

    /**
     * 排序
     * @param sizes
     */
    private void sortSizes(List<Camera.Size> sizes) {
        Collections.sort(sizes, new Comparator<Camera.Size>() {
            @Override
            public int compare(Camera.Size lhs, Camera.Size rhs) {
              return rhs.width - lhs.width;
            }
        });
    }

    /**
     *
     * 以及SurfaceView的比例来计算preview的尺寸
     * @param sizes
     * @param defaultSize
     * @param pictureSize 图片的大小
     * @param minRatio preview短边比长边所接受的最小比例
     * @return
     */
    private Camera.Size findBestPreviewSize(List<Camera.Size> sizes, Camera.Size defaultSize,
                                            Camera.Size pictureSize, float minRatio) {
        final int pictureWidth = pictureSize.width;
        final int pictureHeight = pictureSize.height;
        boolean isBestSize = (pictureHeight / (float)pictureWidth) > minRatio;
        sortSizes(sizes);

        Iterator<Camera.Size> it = sizes.iterator();
        while (it.hasNext()) {
            Camera.Size size = it.next();
            if ((float) size.height / size.width <= minRatio) {
                it.remove();
                continue;
            }

            // 找到同样的比例，直接返回
            if (isBestSize && size.width * pictureHeight == size.height * pictureWidth) {
                return size;
            }
        }

        // 未找到同样的比例的，返回尺寸最大的
        if (!sizes.isEmpty()) {
            return sizes.get(0);
        }

        // 没得选，默认吧
        return defaultSize;
    }

    /**
     * 设置surfaceView显示取景画面
     * @param surfaceView 显示画面的SurfaceView
     * @param previewSizes
     */
    private void setSurfaceView(SurfaceView surfaceView, Camera.Size previewSizes){
//        this.surfaceView = surfaceView;
        if (surfaceView == null){
            throw new  NullPointerException ("surfaceView can not null !");
        }
//        if (null != previewSizes){
//            //根据previewSize来重新设置我们的surfaceView的大小
//            ViewGroup.LayoutParams params = surfaceView.getLayoutParams();
//            params.height = (previewSizes.width / previewSizes.height) * surfaceView.getWidth();
//            surfaceView.setLayoutParams(params);
//        }

        //设置surface不需要自己的维护缓冲区
        surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.setFormat(PixelFormat.TRANSPARENT);//translucent半透明 transparent透明
        surfaceHolder.addCallback(new MySurfaceHolderOfCallback());
    }

    /**
     * 获取图片本地保存的路径
     * @param context 上下文
     */
    private void getLocalSavePath(Context context){
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ){
            //相机拍摄的图片和视频保存的位置
            path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath();
        }else {
            path = Environment.getDataDirectory().getAbsolutePath() + File.separator +
                    context.getPackageName() + File.separator + IMG;
        }

        File file = new File(path);
        if (!file.exists()){
            file.mkdirs();
        }
    }



    /**
     * surface回调监听
     */
    private class MySurfaceHolderOfCallback implements SurfaceHolder.Callback{

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            startPreview();
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            if (camera == null){
                return;
            }
            if (holder.getSurface() != null){
                followScreenOrientation(mContext,camera);
                camera.stopPreview();
                camera.startPreview();
                isPreView = true;
            }
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            stopPreview();
        }
    }

    /**
     * 相机获取JPG照片时激发监听器
     */
    private class MyGetPictureCallback implements Camera.PictureCallback{
        @Override
        public void onPictureTaken(final byte[] data, final Camera camera) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    //根据拍照所得的数据创建位图
                    Bitmap bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
                    String fileName = IMG + System.currentTimeMillis() + JPEG;
                    try {
                        OutputStream os = new FileOutputStream(new File(path,fileName));
                        //图片竟然不能旋转了，故这里要旋转下
                        bitmap = getRotateBitmap(bitmap,90f);
                        boolean sucess = bitmap.compress(Bitmap.CompressFormat.JPEG,100,os);
                        if (sucess){
                            try {
                                os.flush();
                                os.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }

                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    }

                }
            });
            camera.stopPreview();
            camera.startPreview();
            isPreView = true;
            isTokingPicture = false;
        }
    }


    /**
     * 旋转Bitmap
     * @param b
     * @param rotateDegree
     * @return
     */
    public static Bitmap getRotateBitmap(Bitmap b, float rotateDegree){
        Matrix matrix = new Matrix();
        matrix.postRotate((float)rotateDegree);
        Bitmap rotaBitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, false);
        return rotaBitmap;
    }

}
